use super::gp::GP;
use super::rawmem::RawMemory;
use std::alloc::Layout;
use std::fmt;
use std::ops::{Deref, DerefMut, Drop};

pub struct UBox<T> {
    gp: GP,
    data: std::ptr::NonNull<T>,
}

impl<T> UBox<T> {
    pub fn new(data: T, m: &RawMemory) -> Self {
        let layout = Layout::new::<T>();
        let mut gp = GP::default();
        let lptr = m.ualloc(&mut gp, layout.size() as u64);
        match lptr {
            Some(p) => unsafe {
                println!("{:?}", p);
                let mut ptr = std::ptr::NonNull::<T>::new(p as *mut T).unwrap();
                *(ptr.as_mut()) = data;
                UBox { gp: gp, data: ptr }
            },
            None => UBox {
                gp: gp,
                data: std::ptr::NonNull::dangling(),
            },
        }
    }
}
impl<T> fmt::Display for UBox<T>
where
    T: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "gp:{} {:?}", self.gp, self.data)
    }
}
impl<T> Drop for UBox<T> {
    fn drop(&mut self) {}
}
impl<T> Deref for UBox<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        unsafe { self.data.as_ref() }
    }
}
impl<T> DerefMut for UBox<T> {
    type Target = T;
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.data.as_mut() }
    }
}
